package com.ml.loan.common.aspect;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.ml.loan.common.annotaion.OperLog;
import com.ml.loan.common.enums.BusinessStatus;
import com.ml.loan.common.utils.StringUtils;
import com.ml.loan.common.utils.UserAgentGetter;
import com.ml.loan.sys.model.SysOperRecord;
import com.ml.loan.sys.model.User;
import com.ml.loan.sys.service.SysOperRecordService;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.subject.Subject;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.*;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Method;
import java.util.Map;

/**
 * 操作日志记录
 *
 * @author Mickey
 * @date 2022/8/22 11:44
 */
@Aspect
@Component
public class OperLogAspect {

    private ThreadLocal<Long> startTime = new ThreadLocal<>();

    @Autowired
    private SysOperRecordService operRecordService;

    @Pointcut("@annotation(com.ml.loan.common.annotaion.OperLog)")
    public void operLog() {

    }

    @Before("operLog()")
    public void doBefore(JoinPoint joinPoint) throws Throwable {
        startTime.set(System.currentTimeMillis());
    }

    @AfterReturning(pointcut = "operLog()", returning = "result")
    public void doAfterReturning(JoinPoint joinPoint, Object result) {
        saveLog(joinPoint, result, null);
    }

    @AfterThrowing(value = "operLog()", throwing = "e")
    public void doAfterThrowing(JoinPoint joinPoint, Exception e) {
        saveLog(joinPoint, null, e);
    }

    private void saveLog(JoinPoint joinPoint, Object result, Exception e) {
        // 获取reques对象
        ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        HttpServletRequest request = (attributes == null ? null : attributes.getRequest());
        // 构建操作日志
        SysOperRecord operRecord = new SysOperRecord();
        operRecord.setUserId(getLoginUserId());
        operRecord.setUserType(0);
        if (startTime.get() != null) {
            operRecord.setSpendTime(System.currentTimeMillis() - startTime.get());
        }

        if (request != null) {
            operRecord.setRequestMethod(request.getMethod());
            operRecord.setUrl(request.getRequestURI());
            operRecord.setIp(new UserAgentGetter(request).getIP());
        }

        // 记录异常信息
        if (e != null) {
            operRecord.setState(BusinessStatus.FAIL.ordinal());
            operRecord.setComments(StringUtils.substring(e.toString(), 0, 2000));
        }

        // 记录模块名、操作功能、请求方法、请求参数、返回结果
        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
        operRecord.setOperMethod(joinPoint.getTarget().getClass().getName() + "." + signature.getName());
        Method method = signature.getMethod();
        if (method != null) {
            OperLog operLog = method.getAnnotation(OperLog.class);
            if (operLog != null) {
                operRecord.setModel(operLog.module());
                operRecord.setDescription(operLog.desc());
                if (operLog.param() && request != null) {
                    operRecord.setParam(getRequestValue(joinPoint, request));
                }
                if (operLog.result() && result != null) {
                    operRecord.setResult(StringUtils.substring(JSON.toJSONString(result), 0, 2000));
                }
            }
        }
        //保存日志记录
        operRecordService.saveAsync(operRecord);
    }

    /**
     * 获取当前登录用户
     *
     * @param
     * @author caozx
     * @date 2020/7/10 19:31
     **/
    private Integer getLoginUserId() {
        Subject subject = SecurityUtils.getSubject();
        if (subject == null) {
            return null;
        }
        Object object = subject.getPrincipal();
        if (object instanceof User) {
            return ((User) object).getUserId();
        }
        return null;
    }

    /**
     * 获取请求参数
     *
     * @param joinPoint
     * @param request
     * @return
     */
    private String getRequestValue(JoinPoint joinPoint, HttpServletRequest request) {
        Map<String, String[]> map = request.getParameterMap();
        if (StringUtils.isNotEmpty(map)) {
            String params = JSONObject.toJSONString(map);
            return StringUtils.substring(params, 0, 2000);
        } else {
            Object args = joinPoint.getArgs();
            if (StringUtils.isNotNull(args)) {
                String params = argsArrayToString(joinPoint.getArgs());
                return StringUtils.substring(params, 0, 2000);
            }
        }
        return null;
    }

    /**
     * 参数拼装
     */
    private String argsArrayToString(Object[] paramsArray) {
        String params = "" ;
        if (paramsArray != null && paramsArray.length > 0) {
            for (Object o : paramsArray) {
                if (StringUtils.isNotNull(o)) {
                    try {
                        params += JSONObject.toJSONString(o) + " " ;
                    } catch (Exception e) {
                    }
                }
            }
        }
        return params.trim();
    }

}
